import numpy as np
import platgo as pg


class CEC_2010_F1(pg.Problem):

    def __init__(self, D: int = 10) -> None:
        self.name = 'CEC_2010_F1'
        self.type['single'], self.type['real'], self.type['expensive'], self.type['constrained'] = [True] * 4
        self.M = 1
        self.Optimal_des = np.array(
            [0.0308587180874830, -0.0786322923531560, 0.0486511466380380, -0.0690898310663540, -0.0879185429419280,
             0.0889826398111410, 0.0741432356398470, -0.0865275935801490, -0.0206165319039070, 0.0555861064992310,
             0.0592859548835980, -0.0406714855546850, -0.0873999118876930, -0.0184258512574100, -0.00518491279306200,
             -0.0398920379370260, 0.0365092293874580, 0.0260464148544330, -0.0671338629360290, 0.0827801891449430,
             -0.0493367225770620, 0.0185031880809590, 0.0516106191312550, 0.0186131177684320, 0.0934485981816570,
             -0.0712088407808730, -0.0365356778945720, -0.0312612852693300, 0.0992438052479630, 0.0538724459455740])
        self.D = D
        self.D = min(self.D, len(self.Optimal_des))
        lb = [1] * self.D
        ub = [10] * self.D
        self.borders = np.array([lb, ub])
        super().__init__()

    def cal_obj(self, pop: pg.Population) -> None:
        x = pop.decs
        Z = x - np.tile(self.Optimal_des[0: x.shape[1]], (x.shape[0], 1))
        pop.objv = -abs(np.sum((np.power(np.cos(Z), 4)), axis=1) - 2 * np.prod((np.power(np.cos(Z), 2)), axis=1)) \
                   / np.sqrt(np.sum(np.tile(np.arange(1, Z.shape[1] + 1), (Z.shape[0], 1)) * np.power(Z, 2), axis=1))
        Z1 = x - np.tile(self.Optimal_des[0:x.shape[1]], (x.shape[0], 1))
        pop.cv = np.zeros((Z1.shape[0], 2))
        pop.cv[:, 0] = 0.75 - np.prod(Z1, axis=1)
        pop.cv[:, 1] = np.sum(Z, axis=1) - 7.5 * Z.shape[1]

    def get_optimal(self) -> np.ndarray:
        # 均匀采样函数还未完成
        raise NotImplementedError("get optimal has not been implemented")


if __name__ == '__main__':
    d = CEC_2010_F1()
    pop = pg.Population(decs=np.random.uniform(0, 1, (10, 7)))
    print(d.borders)
    # print(pop.decs)
    d.cal_obj(pop)  # 计算目标函数值
    print(pop.objv)
